﻿Public Class Cow

    ' For Walk (Property)
    Public testvar As Boolean
    Public vLeftDirection As Integer
    Public vTopDirection As Integer
    Public vSpeed As Integer
    Public vMaxLeft As Integer
    Public vMaxTop As Integer
    Public vMinLeft As Integer
    Public vMinTop As Integer

    ' For Walk (Variable)
    Private tempSpeed As Integer
    Public MaxWalk As Integer
    Public Stamina As Integer

    'For Cow Property
    Public vAction As Integer
    Public vCleanLevel As Integer
    Public vCowSize As Integer
    Public vHealth As Integer
    Public vMilkingTime As Integer
    Public vMilkingTimeSpeed As Integer
    Public vMilkStatus As Boolean
    Public vMilkType As Integer

    'For Cow variable
    Public LeftTarget As Integer
    Public TopTarget As Integer
    Private AfterAction As Integer
    Private MaxHealth As Integer
    Private MaxHealthWidth As Integer
    Private MaxMilkingTime As Integer
    Private MaxClean As Integer
    Private MaxCleanHeight As Integer
    Private DefaultCleanTop As Integer
    Private TempMTS As Integer
    Private HungryStatus As Boolean
    Private CleanStatus As Boolean
    Private isDie As Boolean

    'Variable for Cow Status
    Public DirtyIconTime As Integer
    Public HungryIconTime As Integer

    'Variable for Milk
    Private MilkingPoints As Integer
    Private MilkValue As Integer
    Private DecMilkValue As Integer

    'Variable for Clean Points
    Private CleaningPoints As Integer

    'Variable for Cow Position
    Private AdditionalPos(1) As Integer

    'Variable for Alternative Error
    Private WalkStatus As Boolean = True 'False if cow is searching for food
    Private RealDirection As Integer ' 0 for left, 1 for right

    Public Property CleanLevel() As Integer
        Get
            Return vCleanLevel
        End Get
        Set(ByVal value As Integer)
            vCleanLevel = value
        End Set
    End Property

    Public Property CowSize() As Integer
        '0 = Small
        '1 = Medium
        '2 = Big
        Get
            Return vCowSize
        End Get
        Set(ByVal value As Integer)
            vCowSize = value
        End Set
    End Property

    Public Property Health() As Integer
        Get
            Return vHealth
        End Get
        Set(ByVal value As Integer)
            vHealth = value
        End Set
    End Property

    Public Property MilkingTime() As Integer
        Get
            Return vMilkingTime
        End Get
        Set(ByVal value As Integer)
            vMilkingTime = value
        End Set
    End Property

    Public Property MilkingTimeSpeed() As Integer
        Get
            Return vMilkingTimeSpeed
        End Get
        Set(ByVal value As Integer)
            vMilkingTimeSpeed = value
        End Set
    End Property

    Public Property MilkStatus() As Boolean
        Get
            Return vMilkStatus
        End Get
        Set(ByVal value As Boolean)
            vMilkStatus = value
        End Set
    End Property

    Public Property MilkType() As Integer
        '0 = Bad
        '1 = Good
        '2 = Best
        Get
            Return vMilkType
        End Get
        Set(ByVal value As Integer)
            vMilkType = value
        End Set
    End Property

    Public Property Action() As Integer
        '0 = Idle
        '1 = Random
        '2 = GoToPlace
        '3 = Eat
        '4 = Cleaning
        Get
            Return vAction
        End Get
        Set(ByVal value As Integer)
            vAction = value
        End Set
    End Property

    Public Property MaxLeft() As Integer
        Get
            Return vMaxLeft
        End Get
        Set(ByVal value As Integer)
            vMaxLeft = value
        End Set
    End Property

    Public Property MaxTop() As Integer
        Get
            Return vMaxTop
        End Get
        Set(ByVal value As Integer)
            vMaxTop = value
        End Set
    End Property

    Public Property MinLeft() As Integer
        Get
            Return vMinLeft
        End Get
        Set(ByVal value As Integer)
            vMinLeft = value
        End Set
    End Property

    Public Property MinTop() As Integer
        Get
            Return vMinTop
        End Get
        Set(ByVal value As Integer)
            vMinTop = value
        End Set
    End Property

    Public Property Speed() As Integer
        Get
            Return vSpeed
        End Get
        Set(ByVal value As Integer)
            vSpeed = value
        End Set
    End Property

    Public Property LeftDirection() As Integer
        '0 = Null
        '1 = Left
        '2 = Right
        Get
            Return vLeftDirection
        End Get
        Set(ByVal value As Integer)
            vLeftDirection = value
        End Set
    End Property

    Public Property TopDirection() As Integer
        '0 = Null
        '1 = Top
        '2 = Bottom
        Get
            Return vTopDirection
        End Get
        Set(ByVal value As Integer)
            vTopDirection = value
        End Set
    End Property

    ' //////////////////////////// END OF PROPERTY ///////////////////////////////// '

    ' ///////////////////////////// METHOD START /////////////////////////////////// '

    Public Sub Walk()
        If (LeftDirection = 1) Then
            If (Me.MinLeft > (Me.Left - Me.Speed)) Then
                ChangeDirection(0, 2)
            Else
                GoLeft()
            End If
        ElseIf (LeftDirection = 2) Then
            If (Me.MaxLeft < (Me.Left + Me.Speed)) Then
                ChangeDirection(0, 1)
            Else
                GoRight()
            End If
        End If
        If TopDirection = 1 Then
            If (Me.MinTop > (Me.Top - Me.Speed)) Then
                ChangeDirection(1, 2)
            Else
                GoUp()
            End If
        ElseIf TopDirection = 2 Then
            If (Me.MaxTop < (Me.Top + Me.Speed)) Then
                ChangeDirection(1, 1)
            Else
                GoDown()
            End If
        End If
    End Sub

    Public Overloads Sub ChangeDirection()
        Dim acak As New Random

        Me.LeftDirection = acak.Next(3)
        Me.TopDirection = acak.Next(3)
    End Sub

    Public Overloads Sub ChangeDirection(ByVal Type As Integer, ByVal dir As Integer)
        '0 = Left
        '1 = Top
        Select Case Type
            Case 0
                Me.LeftDirection = dir
            Case 1
                Me.TopDirection = dir
        End Select

    End Sub

    Public Overloads Sub ChangeDirection(ByVal Opposite As Boolean)
        If Opposite Then
            If Me.LeftDirection = 1 Then
                ChangeDirection(0, 2)
            ElseIf Me.LeftDirection = 2 Then
                ChangeDirection(0, 1)
            End If

            If Me.TopDirection = 1 Then
                ChangeDirection(1, 2)
            ElseIf Me.LeftDirection = 2 Then
                ChangeDirection(1, 1)
            End If
        End If
    End Sub

    Public Sub GoLeft()
        Me.Left -= Me.Speed
        If (WalkStatus = True) Then
            AdditionalPos(0) = 0
        End If

        If (RealDirection = 1) Then
            RealDirection = 0
            ChangeCowSize(CowSize)
        End If

    End Sub

    Public Sub GoRight()
        Me.Left += Me.Speed
        AdditionalPos(0) = CowImage.Left + CowImage.Width

        If (RealDirection = 0) Then
            RealDirection = 1
            ChangeCowSize(CowSize)
        End If

    End Sub

    Public Sub GoUp()
        Me.Top -= Me.Speed
    End Sub

    Public Sub GoDown()
        Me.Top += Me.Speed
    End Sub

    Private Overloads Sub GoToPlace(ByVal x As Integer, ByVal y As Integer)
        GoToPlace(x, y, 2)
    End Sub

    Private Overloads Sub GoToPlace(ByVal x As Integer, ByVal y As Integer, ByVal action As Integer)
        Me.Speed = tempSpeed
        LeftTarget = x
        TopTarget = y
        Me.Action = action
    End Sub

    Public Sub RandomWalk()
        If (Stamina > 0 And Speed > 0) Then
            Walk()
            Stamina -= 1
        ElseIf Stamina = 0 Then
            tempSpeed = vSpeed
            vSpeed = 0
        End If

        If Stamina >= MaxWalk Then
            vSpeed = tempSpeed
            ChangeDirection()
        End If

        If vSpeed = 0 Then
            Stamina += 1
        End If
    End Sub

    Public Sub ShowCowStatus(ByVal status As Integer)
        '0 = Milk Status
        '1 = Clean Status
        '2 = Hungry Status

        Select Case status
            Case 0
                If (MilkIcon.Visible = False) Then
                    MilkIcon.Visible = True
                End If
            Case 1
                If (CleanIcon.Visible = False) Then
                    CleanIcon.Visible = True
                End If
            Case 2
                If (HungryIcon.Visible = False) Then
                    HungryIcon.Visible = True
                End If
        End Select

    End Sub

    Public Sub HideCowStatus(ByVal status As Integer)
        Select Case status
            Case 0
                If (MilkIcon.Visible = True) Then
                    MilkIcon.Visible = False
                End If
            Case 1
                If (CleanIcon.Visible = True) Then
                    CleanIcon.Visible = False
                End If
            Case 2
                If (HungryIcon.Visible = True) Then
                    HungryIcon.Visible = False
                End If
        End Select
    End Sub

    Public Sub ToggleCowStatus(ByVal status As Integer)

        Select Case status
            Case 0
                MilkIcon.Visible = Not MilkIcon.Visible
            Case 1
                CleanIcon.Visible = Not CleanIcon.Visible
            Case 2
                HungryIcon.Visible = Not HungryIcon.Visible
        End Select

    End Sub

    Public Sub ChangeCowSize(ByVal size As Integer)
        Dim realsize As Integer
        realsize = size * 2 + RealDirection
        CowImage.Image = CowList.Images(realsize)
    End Sub

    'Private Sub ChangeMilkPoints(ByVal Points As Integer, ByVal Money As Integer)
    '    MilkingPoints = Points
    '    TotalMilkingMoney += Money
    'End Sub

    Private Function GetFoodAmount()
        Dim FoodAmount As Integer = 0

        If (isDie = False) Then

            For Each obj As Object In Parent.Controls
                If TypeOf (obj) Is Food Then
                    FoodAmount += 1
                End If
            Next

        End If

        Return FoodAmount
    End Function

    Private Function GetServantAmount()
        Dim ServantAmount As Integer = 0
        If (isDie = False) Then
            For Each obj As Object In Parent.Controls
                If TypeOf (obj) Is Servant Then
                    If obj.Availability = True Then
                        ServantAmount += 1
                    End If
                End If
            Next
        End If

        Return ServantAmount

    End Function

    Public Sub CowMove()
        Dim overleft As Integer
        If (Me.Left < LeftTarget) Then
            overleft = (LeftTarget - Me.Left) Mod Me.Speed
            Me.Left += overleft
            GoRight()
            LeftDirection = 2
        ElseIf (Me.Left > LeftTarget) Then
            overleft = (Me.Left - LeftTarget) Mod Me.Speed
            Me.Left -= overleft
            GoLeft()
            LeftDirection = 1
        End If

        Dim overtop As Integer
        If (Me.Top < TopTarget) Then
            overtop = (TopTarget - Me.Top) Mod Me.Speed
            Me.Top += overtop
            GoDown()
        ElseIf (Me.Top > TopTarget) Then
            overtop = (Me.Top - TopTarget) Mod Me.Speed
            Me.Top -= overtop
            GoUp()
        End If

    End Sub

    Public Sub GoToFood()
        'Search Food Function

        Dim FoodAmount As Integer = GetFoodAmount()

        If (FoodAmount > 0) Then

            Dim ChosenFood(1) As Integer
            Dim CowPos(1) As Integer

            'Dim AdditionalPos(1) As Integer
            'AdditionalPos(0) = 0
            'AdditionalPos(1) = 0

            CowPos(0) = Me.Left + AdditionalPos(0)
            CowPos(1) = Me.Top - AdditionalPos(1)
            ChosenFood(0) = 0 'For Food Element
            ChosenFood(1) = Parent.Width + Parent.Height 'For Total Different

            For i As Integer = 0 To FoodAmount - 1
                Dim FoodPos(1) As Integer
                Dim RealCowPos(1) As Integer
                Dim FoodVar As Food = Parent.Controls.OfType(Of Food).ElementAt(i)

                Dim TotalDifferent As Integer
                Dim Different(1) As Integer

                Different(0) = 0
                Different(1) = 0

                RealCowPos(0) = CowPos(0) - (FoodVar.Width / 2)
                RealCowPos(1) = CowPos(1) - (FoodVar.Height / 2)

                FoodPos(0) = FoodVar.Left
                FoodPos(1) = FoodVar.Top

                For x As Integer = 0 To UBound(FoodPos)
                    If (FoodPos(x) > RealCowPos(x)) Then
                        Different(x) = FoodPos(x) - RealCowPos(x)
                    Else
                        Different(x) = RealCowPos(x) - FoodPos(x)
                    End If
                Next

                TotalDifferent = Different.Sum

                If (TotalDifferent < ChosenFood(1)) Then
                    ChosenFood(0) = i
                    ChosenFood(1) = TotalDifferent

                End If
            Next

            Dim FoodLocation(1) As Integer
            Dim FoodVariable As Food = Parent.Controls.OfType(Of Food).ElementAt(ChosenFood(0))

            FoodLocation(0) = FoodVariable.Left + (FoodVariable.Width / 2)
            FoodLocation(1) = FoodVariable.Top + (FoodVariable.Height / 2)

            If (FoodLocation(0) > Me.Left And FoodLocation(0) < CowPos(0)) Then


                Dim DifferentLPos As Integer = CowPos(0) - FoodLocation(0)
                Dim AdditionalLoc As Integer = CowImage.Width
                If (DifferentLPos < (CowImage.Width / 2)) Then
                    AdditionalLoc = 0 - AdditionalLoc
                    WalkStatus = False
                End If

                FoodLocation(0) += AdditionalLoc
            End If

            FoodLocation(0) -= AdditionalPos(0)
            FoodLocation(1) -= AdditionalPos(1)

            If (CleanStatus = True) Then
                GoToPlace(FoodLocation(0), FoodLocation(1), 3)
            End If

            If (Me.Left = LeftTarget And Me.Top = TopTarget) Then
                EatFood(ChosenFood(0))
            End If

        Else
            Action = 1
        End If

    End Sub

    Public Sub EatFood(ByVal FoodElement As Integer)

        Dim FoodAmount As Integer = GetFoodAmount()
        Dim CowPos(1) As Integer

        CowPos(0) = Me.Left + AdditionalPos(0)
        CowPos(1) = Me.Top + AdditionalPos(1)

        'For i As Integer = 0 To FoodAmount - 1
        '    Dim xFood As Integer = Parent.Controls.OfType(Of Food).ElementAt(i).Left + AdditionalPos(0)
        '    Dim yFood As Integer = Parent.Controls.OfType(Of Food).ElementAt(i).Top + AdditionalPos(1)

        '    If (xFood = CowPos(0) And yFood = CowPos(1)) Then
        '        FoodElement = i
        '    End If
        'Next

        Dim FoodValue As Integer
        FoodValue = Parent.Controls.OfType(Of Food).ElementAt(FoodElement).FoodValue
        Parent.Controls.OfType(Of Food).ElementAt(FoodElement).Eaten()

        'Clear Walk Status for search food
        WalkStatus = True

        DecreaseMilkingTime()
        MilkValue += FoodValue

        ChangeMilkType()

        RefreshCow(2)
        Me.Action = 1
    End Sub

    Public Sub ChangeMilkType()
        'Cow Size Settings
        Dim size As Integer

        If (MilkValue >= 25) Then
            size = 2
            DecMilkValue = 12
        ElseIf (MilkValue >= 10) Then
            size = 1
            DecMilkValue = 8
        Else
            size = 0
            DecMilkValue = 6
        End If

        MilkType = size
        CowSize = size
        ChangeCowSize(size)
    End Sub

    Private Sub CheckCowStatus()
        'Check Clean level
        If (CleanLevel <= DirtyIconTime) Then
            ShowCowStatus(1)
        End If

        If (CleanLevel = 0) Then
            MilkStatus = False
            CleanStatus = False
            HideCowStatus(0)
            If (Action = 3) Then
                Action = 1
            End If
        End If

        'Check Milk Status
        If (MilkingTime = 0 And CleanStatus = True) Then
            ShowCowStatus(0)
            MilkStatus = True
        End If

        'Check Health Status
        If (Health <= HungryIconTime) Then
            ShowCowStatus(2)
            If (CleanStatus = True) Then
                HungryStatus = True
                GoToFood()
            End If
        End If
    End Sub

    Public Overloads Sub DecreaseHealth()
        DecreaseHealth(1)
    End Sub

    Public Overloads Sub Dead()
        Dead(False)
    End Sub

    Public Overloads Sub Dead(ByVal stolen As Boolean)
        Parent.Controls.OfType(Of StatusPoints).ElementAtOrDefault(0).DecreaseLife()
        isDie = True
        Pause(True)
        If (stolen = False) Then
            Timer2.Enabled = True
            CowImage.Image = CowList.Images(CowList.Images.Count - 1)
        Else
            Me.Dispose()
        End If
    End Sub

    Public Overloads Sub DecreaseHealth(ByVal Damage As Integer)
        If (Health > 0) Then
            Health -= Damage

            If (Health <= 0) Then
                HealthBar.Width = 0
                Dead()
            Else
                HealthBar.Width = Health * MaxHealthWidth / MaxHealth
            End If
        End If
    End Sub

    Public Sub DecreaseMilkingTime()
        If (MilkingTime > 0) Then
            MilkingTime -= MilkingTimeSpeed
        End If
    End Sub

    Public Sub DecreaseCleanLevel()

        If (CleanLevel > 0) Then
            CleanLevel -= 1
            CleanBar.Top = DefaultCleanTop + (MaxClean - CleanLevel) * MaxCleanHeight / MaxClean
            CleanBar.Height = CleanLevel * MaxCleanHeight / MaxClean
        End If
    End Sub

    Public Sub StartAction(ByVal act As Integer)
        '0 for milking
        '1 for cleaning

        Dim ServantAmount As Integer = GetServantAmount()

        If (ServantAmount > 0) Then
            Dim TotalServant As Integer = Parent.Controls.OfType(Of Servant).Count

            For i = 0 To TotalServant - 1
                Dim ChosenServant As Servant = Parent.Controls.OfType(Of Servant).ElementAt(i)
                Pause(True)
                If (ChosenServant.Availability = True) Then
                    ChosenServant.Left = Me.Left + ((Me.Width - ChosenServant.Width) / 2)
                    ChosenServant.Top = Me.Top + (Me.Height - ChosenServant.Height)
                    If (act = 0) Then
                        ChosenServant.Milking(Me)
                    Else
                        ChosenServant.Cleaning(Me)
                    End If

                    i = TotalServant
                End If
            Next
        End If
    End Sub

    Public Sub StartMilking()
        StartAction(0)
    End Sub

    Public Sub StartCleaning()
        StartAction(1)
    End Sub

    Public Sub Milking()
        If (MilkStatus = True) Then
            AddPoints(MilkingPoints, MilkValue)
            MilkValue -= DecMilkValue

            RefreshCow(0)
            ChangeMilkType()
            Pause(False)
        End If
    End Sub

    Public Sub Cleaning()
        AddPoints(CleaningPoints)
        RefreshCow(1)
    End Sub

    Public Overloads Sub RefreshCow(ByVal Type As Integer)
        Select Case Type
            Case 0
                RefreshCow(True, False, False)
            Case 1
                RefreshCow(False, True, False)
            Case 2
                RefreshCow(False, False, True)
        End Select
    End Sub

    Public Overloads Sub RefreshCow(ByVal MilkTime As Boolean, ByVal CleanStat As Boolean, ByVal HealthStat As Boolean)

        If (MilkTime = True) Then
            MilkingTime = MaxMilkingTime
            HideCowStatus(0)
        End If

        If (CleanStat = True) Then
            CleanLevel = MaxClean
            CleanBar.Height = MaxCleanHeight
            HideCowStatus(1)
            CleanStatus = True
        End If

        If (HealthStat = True) Then
            HungryStatus = False
            Health = MaxHealth
            HealthBar.Width = MaxHealthWidth
            HideCowStatus(2)
        End If

    End Sub

    Private Overloads Sub AddPoints(ByVal Points As Integer)
        AddPoints(Points, 0)
    End Sub

    Private Overloads Sub AddPoints(ByVal Points As Integer, ByVal Money As Integer)
        With Parent.Controls.OfType(Of StatusPoints).ElementAtOrDefault(0)
            .AddPoints(Points)
            .IncreaseMoney(Money)
        End With
    End Sub

    Public Sub Pause(ByVal status As Boolean)
        Timer1.Enabled = Not status
    End Sub

    Public Sub SetDefaultValue(ByVal Var As Integer, ByVal Value As Integer)

        If (Var = 0) Then
            Var = Value
        End If

    End Sub

    ' //////////////////////////// END OF METHOD ///////////////////////////////// '

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick

        'Change Cow Status
        DecreaseHealth()
        DecreaseCleanLevel()
        CheckCowStatus()

        Select Case Action
            Case 0

            Case 1
                ' Action = Random
                RandomWalk()
            Case 2
                ' Action = Go to specific place
                CowMove()
            Case 3
                CowMove()
        End Select

    End Sub

    Private Sub Cow_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        'Default Settings for Cow

        SetDefaultValue(MaxLeft, 200)
        SetDefaultValue(MaxTop, 200)
        SetDefaultValue(MinLeft, 50)
        SetDefaultValue(MinTop, 50)

        With Me
            .Speed = 2
            .MaxWalk = 10
            .MaxHealth = 500
            .MaxClean = 500
            .DefaultCleanTop = CleanBar.Top
            .CleaningPoints = 150
            .MilkingPoints = 200
            .MaxMilkingTime = 3
            .MilkingTimeSpeed = 1
            .MilkValue = 0
            .DecMilkValue = 5
            .HungryStatus = False
            .CleanStatus = True
            .isDie = False
        End With

        With Me
            .tempSpeed = Speed
            .LeftDirection = 0
            .TopDirection = 0
            .Stamina = MaxWalk
            .Action = 1
            .AfterAction = 1
            .Health = MaxHealth
            .MaxHealthWidth = HealthBar.Width
            .CleanLevel = MaxClean
            .MaxCleanHeight = CleanBar.Height
            .MilkingTime = MaxMilkingTime
            .TempMTS = MilkingTimeSpeed
            .HungryIconTime = 475
            .DirtyIconTime = MaxClean / 2
        End With

        Dim acak As New Random

        CowImage.Image = CowList.Images(acak.Next(2))
        MilkIcon.Image = IconList.Images(0)
        CleanIcon.Image = IconList.Images(1)
        HungryIcon.Image = IconList.Images(2)

        AdditionalPos(0) = 0
        AdditionalPos(1) = (CowImage.Top + CowImage.Height)

        Me.BringToFront()
    End Sub

    Private Sub MilkIcon_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MilkIcon.Click
        If (MilkStatus = True) Then
            StartMilking()
        End If
    End Sub

    Private Sub CleanIcon_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CleanIcon.Click
        'Condition Here
        StartCleaning()
    End Sub

    Private Sub Timer2_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer2.Tick
        Me.Dispose()
    End Sub

End Class